<template>
    <div>
        <!-- <el-button @click="getLocationByAmap">高德定位</el-button> -->
        <AMapView @updateMap="updateMap" :updateCoordsy="updateCoordsy" :can-change-layer="true"></AMapView>
        <div>
            <SpeedGauge class="speedSetting" :speed="speed" style="height: 150px;width: 150px"></SpeedGauge>
            <div class="speedSetting info">
                <!-- <el-button @click="getLocationByJs">js定位</el-button> -->
                <el-button :disabled="uploadDate.isStartWatch" @click="startPath" circle :icon="VideoPlay"
                    type="primary" size="medium"></el-button>
                <el-button :disabled="!uploadDate.isStartWatch" @click="pausePath" circle :icon="VideoPause"
                    type="info" size="medium"></el-button>
                <el-button :disabled="!(uploadDate.positions.length > 1)" @click="stopPath" circle
                    :icon="Finished" type="success" size="medium"></el-button>
                <el-button @click="export2JSON"
                    v-if="!uploadDate.isStartWatch && uploadDate.positions.length !== 0">导出</el-button>
                <div class="info">跟踪:<el-switch v-model="uploadDate.followPosition" /></div>
                <div class="info">模拟:<el-switch v-model="simulationData.startPositionSimulation"
                        :disabled="(uploadDate.positions.length > 1)" /></div>
                <span class="info" id="currentPosition">{{ currentPositionText }}</span>
                <span class="info">定位精度:{{ accuracy }}米</span>
            </div>
        </div>
    </div>
</template>

<script lang="ts" setup name="MapTravel">
import { ref, computed, onBeforeUnmount } from 'vue';
//@ts-ignore
import AMapLoader from "@amap/amap-jsapi-loader";
import { reqPostPolyline } from "@/api/polyline";
import { requestGetData, requestIsSuccess } from "@/api/request";
import { convert_gps84_To_Gcj02, MapCoordSys, MapType } from "@/class/map/myMapOpt";
import SpeedGauge from "@/views/map/travel/SpeedGauge.vue";
import { successMessage } from "@/utils/message";
import { MapData } from "@/class/map/MapData";
import { Polyline, PolylineData } from "@/class/map/Polyline";
import { PolygonData } from "@/class/map/Polygon";
import { simulationPositions } from "@/utils/data";
import AMapView from "@/views/map/container/AMapView.vue";
// import img from "@/static/sirection.svg";
import { reqPutAddPath, reqPostTrack } from "@/api/track";
import { Track, TrackData } from "@/class/map/Track";
import { getColorBySpeed } from "@/utils/map_color";
import { Finished, VideoPause, VideoPlay } from '@element-plus/icons-vue';

// 定义常量
const currentPositionName = "currentPosition";
const uploadPositionsTime = 5 * 1000;

// 定义响应式数据
const uploadDate = ref({
    positions: [] as any[],
    speeds: [],
    navigatorWatch: '' as any,
    followPosition: true,
    isStartWatch: false,
    startIndexWithoutUpload: 0,
    uploadInterval: undefined,
    wakeLock: undefined,
    id: undefined,
    dataId: undefined
});
const positionsExtDataSpeed = ref<{ index: number; speed: string; time: number }[]>([]);
const speed = ref(0);
const accuracy = ref(0);
const currentPositionOpt = ref({
    position: undefined,
    extData: {
        name: currentPositionName,
        id: undefined
    },
    icon: undefined,
    offset: [-18, -18],
    rotate: -45
});
const map = ref();
const mapCoordSys = ref(MapCoordSys.CJ02);
const canChangeLayer = ref(true);
const currentPositionMapData = ref();
const simulationData = ref({
    startPositionSimulation: false,
    positionSimulationInterval: undefined,
    simulationPositions: simulationPositions
});

// 计算属性
const currentPositionText = computed(() => {
    const c = 3;
    let result;
    if (typeof currentPositionOpt.value.position !== "undefined") {
        result = "经度:" + currentPositionOpt.value.position[0].toFixed(c) + " " +
            "纬度:" + currentPositionOpt.value.position[1].toFixed(c);
    } else {
        result = "未开启";
    }
    return result;
});

// 方法
const updateCoordsy = (coordsy: string) => {
    // 实现逻辑
};

const updateMap = (newMap: any) => {
    map.value = newMap;
    currentPositionOpt.value.icon = new AMap["Icon"]({
        // image: img,
        imageSize: [36, 36]
    });
    if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition((position) => {
            const { longitude, latitude } = position.coords;
            map.value.setCenter([longitude, latitude]);
        }, (e) => {
            // 处理定位失败
        }, {
            enableHighAccuracy: true,
            timeout: 5000,
            maximumAge: 0
        });
    } else {
        alert('error');
    }
};

const initMap = (position: number[]) => {
    AMapLoader
        .load({
            key: "99df1adfafd916e84e7b953d75c626d7",
            version: "2.0",
            plugins: ['AMap.MouseTool']
        })
        .then((AMap) => {
            map.value = new AMap.Map("container", {
                zoom: 15,
                center: position
            });
            currentPositionOpt.value.icon = new AMap["Icon"]({
                // image: img,
                imageSize: [36, 36]
            });
        })
        .catch((e) => {
            console.log(e);
        });
};

const getLocationByJs = () => {
    if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(navigatorPositionSuccess, (e) => {
            // 处理定位失败
        }, {
            enableHighAccuracy: true,
            timeout: 5000,
            maximumAge: 0
        });
    } else {
        alert('error');
    }
};

const startPath = () => {
    if (navigator.geolocation) {
        if (typeof uploadDate.value.id === "undefined") {
            const myConfig = getConfig();
            reqPostTrack(myConfig).then((result) => {
                uploadDate.value.id = result.data.id;
                uploadDate.value.dataId = result.data.dataId;
                currentPositionOpt.value.extData.id = uploadDate.value.dataId;
            });
        }
        uploadDate.value.uploadInterval = setInterval(uploadPositionsInterval, uploadPositionsTime);
        if (!simulationData.value.startPositionSimulation) {
            uploadDate.value.navigatorWatch = navigator.geolocation.watchPosition(
                navigatorPositionSuccess,
                (e) => { },
                {
                    enableHighAccuracy: true,
                    timeout: 5000,
                    maximumAge: 0
                }
            );
        } else {
            simulationData.value.positionSimulationInterval = setInterval(() => {
                const startIndex = uploadDate.value.positions.length;
                navigatorPositionSuccess({
                    coords: {
                        longitude: simulationData.value.simulationPositions[startIndex][0],
                        latitude: simulationData.value.simulationPositions[startIndex][1],
                        speed: 5,
                        accuracy: 1
                    }
                });
            }, uploadPositionsTime / 10);
            successMessage("开启定位模拟");
        }
        uploadDate.value.isStartWatch = true;
        navigator.wakeLock.request('screen').then((result) => {
            uploadDate.value.wakeLock = result;
            successMessage("保存屏幕常亮");
        });
    } else {
        // 处理错误
    }
};

const stopPath = () => {
    if (uploadDate.value.isStartWatch) {
        pausePath();
    }
    uploadDate.value.positions = [];
    currentPositionOpt.value.position = undefined;
    uploadDate.value.id = undefined;
    currentPositionMapData.value?.setMap();
    map.value.getAllOverlays().forEach((item: any) => {
        item.setOptions({
            ...item.getOptions(),
            "strokeColor": "#a7d714"
        });
    });
};

const pausePath = () => {
    speed.value = 0;
    uploadPositionsInterval();
    if (!simulationData.value.startPositionSimulation) {
        navigator.geolocation.clearWatch(uploadDate.value.navigatorWatch);
    } else {
        clearInterval(simulationData.value.positionSimulationInterval);
    }
    clearInterval(uploadDate.value.uploadInterval);
    uploadDate.value.isStartWatch = false;
    uploadDate.value.wakeLock.release().then(() => uploadDate.value.wakeLock = null);
};

const getConfig = (start = 0, end = uploadDate.value.positions.length - 1): TrackData => {
    const config = new TrackData({
        featureData: new MapData({
            id: uploadDate.value.id,
            type: MapType.Track,
            coordsys: MapCoordSys.GPS,
            name: "位置" + Date.now()
        }),
        featureMap: new Track({
            id: uploadDate.value.dataId,
            path: uploadDate.value.positions.slice(start, end),
            extData: {},
            speed: []
        })
    });
    return config;
};

const export2JSON = () => {
    const myTravel = getConfig()
    myTravel.getJSON();
};

const addPosition2Data = (position: number[]) => {
    uploadDate.value.positions.push(position);
};

const navigatorPositionSuccess = (position: { coords: { longitude: number; latitude: number; accuracy: number; speed: number } }) => {
    const speedFlag = 1;
    const accuracyFlag = 10;
    const { longitude, latitude, accuracy: posAccuracy } = position.coords;
    accuracy.value = parseFloat(posAccuracy.toFixed(2));
    let tempSpeed = (position.coords.speed * 3.6);
    speed.value = parseFloat(tempSpeed.toFixed(2));
    if (accuracy.value > accuracyFlag || speed.value < speedFlag) {
        return;
    }
    let positionConverted: number[];
    if (mapCoordSys.value === MapCoordSys.CJ02) {
        positionConverted = convert_gps84_To_Gcj02([longitude, latitude]);
    } else {
        positionConverted = [longitude, latitude];
    }
    if (uploadDate.value.followPosition) {
        map.value.setCenter(positionConverted);
    }
    if (typeof currentPositionOpt.value.position !== "undefined") {
        const currentPolyline = {
            path: [currentPositionOpt.value.position, positionConverted],
            strokeColor: getColorBySpeed(tempSpeed)
        };
        const myPolyline = new AMap.Polyline(currentPolyline);
        map.value.add(myPolyline);
        if (speed.value > 2) {
            const angle = calAngle(
                currentPositionOpt.value.position[0],
                currentPositionOpt.value.position[1],
                positionConverted[0],
                positionConverted[1]
            );
            currentPositionOpt.value.rotate = angle - 45;
        }
        currentPositionMapData.value.setOptions({
            position: positionConverted,
            rotate: currentPositionOpt.value.rotate
        });
    } else {
        currentPositionOpt.value.position = positionConverted;
        currentPositionMapData.value = new AMap.Marker({position:currentPositionOpt.value.position});
        map.value.add(currentPositionMapData.value);
    }
    currentPositionOpt.value.position.splice(0, 2, positionConverted[0], positionConverted[1]);
    if (uploadDate.value.isStartWatch) {
        uploadDate.value.positions.push([longitude, latitude]);
        uploadDate.value.speeds.push({
            index: uploadDate.value.positions.length - 1,
            speed: tempSpeed,
            time: Date.now()
        });
        if (speed.value > 1) {
            positionsExtDataSpeed.value.push({
                index: uploadDate.value.positions.length - 1,
                speed: tempSpeed.toString(),
                time: Date.now()
            });
        }
    }
};

const calAngle = (cx: number, cy: number, x: number, y: number) => {
    const radian = getCosBy2pt(x, y, cx, cy);
    let angle = Math.acos(radian) * 180 / Math.PI;
    if (x < cx) angle = -angle;
    return angle;

    function getCosBy2pt(x: number, y: number, cx: number, cy: number) {
        let a = [x - cx, y - cy];
        let b = [0, 1];
        return calCos(a, b);
    }

    function calCos(a: number[], b: number[]) {
        let dotProduct = a[0] * b[0] + a[1] * b[1];
        let d = Math.sqrt(a[0] * a[0] + a[1] * a[1]) * Math.sqrt(b[0] * b[0] + b[1] * b[1]);
        return dotProduct / d;
    }
};

const uploadPositionsInterval = async () => {
    if (uploadDate.value.startIndexWithoutUpload < uploadDate.value.positions.length) {
        if (uploadDate.value.id) {
            const startIndex = uploadDate.value.startIndexWithoutUpload;
            const endIndex = uploadDate.value.positions.length - 1;
            const data = new Track({
                id: uploadDate.value.dataId,
                path: uploadDate.value.positions.slice(startIndex, endIndex),
                speed: uploadDate.value.speeds.slice(startIndex, endIndex)
            });
            const result = await reqPutAddPath(data);
                uploadDate.value.startIndexWithoutUpload = endIndex + 1;
        }
    }
};

// 生命周期钩子
onBeforeUnmount(() => {
    stopPath();
});
</script>

<style scoped>
#map {
    width: 100%;
    position: relative;
    height: 400px;
}

#container {
    height: 100%;
    position: relative;
}

.mapinfo {
    background-color: skyblue;
    position: absolute;
    right: 0;
    bottom: 0;
    display: inline-block;
}

.mapinfo div {
    text-align: center;
}

.speedSetting {
    display: inline-block;
    width: 180px;
    float: left;
}

.info {
    margin: 5px;
}
</style>